package com.naiterui.ehp.bs.patient.handler;

import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import com.naiterui.common.redis.RedisUtil;
import com.naiterui.ehp.bp.bo.patient.MsgMaPublishParamBO;
import com.naiterui.ehp.bp.bo.subscribe.AdvisoryReminderBO;
import com.naiterui.ehp.bp.bo.subscribe.InquiryRemindBO;
import com.naiterui.ehp.bp.bo.subscribe.PrescriptionPayBO;
import com.naiterui.ehp.bp.bo.subscribe.ReceiptReminderBO;
import com.naiterui.ehp.bp.bo.subscribe.RefundNoticeBO;
import com.naiterui.ehp.bp.bo.subscribe.ServiceEvaluationBO;
import com.naiterui.ehp.bp.bo.subscribe.ShipNoticeBO;
import com.naiterui.ehp.bp.constants.CommonConstant;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bs.patient.feign.EmrFeginClient;
import com.naiterui.ehp.bs.patient.feign.RecomFeginClient;
import com.naiterui.ehp.bs.patient.feign.WxFeignClient;
import com.naiterui.ehp.bs.patient.handler.data.WxMaMsgData;
import com.naiterui.ehp.bs.patient.handler.data.WxMaMsgEvent;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 微信小程序用户主动消息发送事件处理
 *
 * @author yangfuya
 * @version 1.0
 * @date 2021/5/25 16:27
 **/
@Slf4j
@Component
@AllArgsConstructor
public class WxMaMsgHandler {
    private static final String INQUIRY_CONTENT = "无";
    private static final String PROMPT_DESC = "点击查看详细内容";
    private final WxFeignClient wxFeignClient;
    private final EmrFeginClient emrFeginClient;
    private final RecomFeginClient recomFeginClient;

    /**
     * 发布文本
     *
     * @param wxMaMsgEvent 微信小程序事件监听
     */
    @Async
    @EventListener(classes = WxMaMsgEvent.class, condition = "#root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.TEXT)
    public void publishMsg2Text(WxMaMsgEvent wxMaMsgEvent) {
        WxMaMsgData msgData = wxMaMsgEvent.getEventData();
        String hget = RedisUtil.hashOps().hget(CommonConstant.CONSULT_PATIENT_AIM_DISEASE, msgData.getPatientId() + "_" + msgData.getDoctorId());
        log.info("文本消息：msgData：{}, hget: {}", JSONUtil.toJsonStr(msgData), hget);
        if (StrUtil.isBlank(hget)) {
            hget = "病情咨询";
        }
        this.doPublisInquiryRemind(msgData, "/pages/consult/chat/chat?doctorId=" + msgData.getDoctorId(), hget, msgData.getContent(), PROMPT_DESC);
    }

    /**
     * 发布多媒体（图片、音频、视频、小视频、病历、处方、随访）
     *
     * @param wxMaMsgEvent
     *            微信小程序事件监听
     */
    @Async
    @EventListener(classes = WxMaMsgEvent.class,
            condition = "#root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.IMAGE +
                    " || #root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.VOICE +
                    " || #root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.VIDEO +
                    " || #root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.SHORTVIDEO +
                    " || #root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.MEDICALRECORD +
            " || #root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.RECOMMEND + " || #root.args[0].msgType == "
            + MsgMaPublishParamBO.MsgType.FOLLOW_UP_NOT_STARTED)
    public void publishMsg2Nomal(WxMaMsgEvent wxMaMsgEvent) {
        WxMaMsgData msgData = wxMaMsgEvent.getEventData();
        String msgView;
        String promptDesc = PROMPT_DESC;
        switch (wxMaMsgEvent.getMsgType()) {
            case MsgMaPublishParamBO.MsgType.IMAGE:
                msgView = "【图片】";
                break;
            case MsgMaPublishParamBO.MsgType.VOICE:
                msgView = "【语音】";
                break;
            case MsgMaPublishParamBO.MsgType.VIDEO:
            case MsgMaPublishParamBO.MsgType.SHORTVIDEO:
                msgView = "【视频】";
                break;
            case MsgMaPublishParamBO.MsgType.MEDICALRECORD:
                msgView = "【电子病历】";
                break;
            case MsgMaPublishParamBO.MsgType.RECOMMEND:
                msgView = "【电子处方】";
                break;
            case MsgMaPublishParamBO.MsgType.FOLLOW_UP_NOT_STARTED:
                msgView = "您有一条新的随访任务，请即时处理。";
                promptDesc = "您可以直接点击进入随访任务";
                break;
            default:
                return;
        }
        String hget = RedisUtil.hashOps().hget(CommonConstant.CONSULT_PATIENT_AIM_DISEASE, msgData.getPatientId() + "_" + msgData.getDoctorId());
        log.info("多媒体消息：msgData：{}， msgView：{}, hget: {}", JSONUtil.toJsonStr(msgData), msgView, hget);
        if (StrUtil.isBlank(hget)) {
            hget = "病情咨询";
        }
        if (wxMaMsgEvent.getMsgType() == MsgMaPublishParamBO.MsgType.RECOMMEND) {
            String content = msgData.getContent();
            JSONObject jsonObject = JSONUtil.parseObj(content);
            if (jsonObject.containsKey("recommandId")) {
                Integer type = recomFeginClient.getRecommendTypeById(jsonObject.getLong("recommandId"));
                hget = type == 2 ? "申请续方" : hget;
            }
        }

        this.doPublisInquiryRemind(msgData, "/pages/consult/chat/chat?doctorId=" + msgData.getDoctorId(), hget, msgView,
            promptDesc);
    }

    /**
     * 发布视频问诊
     *
     * @param wxMaMsgEvent 微信小程序事件监听
     */
    @Async
    @EventListener(classes = WxMaMsgEvent.class, condition = "#root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.VIDEO_CONSULT)
    public void publishMsg2VideoConsult(WxMaMsgEvent wxMaMsgEvent) {
        WxMaMsgData msgData = wxMaMsgEvent.getEventData();
        if (StrUtil.isBlank(msgData.getOpenId())) {
            log.error("推送视频问诊失败：{}", JSONUtil.toJsonStr(msgData));
            return;
        }
        log.info("视频问诊消息：msgData：{}", JSONUtil.toJsonStr(msgData));
        this.doPublisInquiryRemind(msgData, msgData.getTargetPage(), msgData.getDiseaseId(), msgData.getContent(),
            PROMPT_DESC);
    }

    /**
     * 发布服务评价
     *
     * @param wxMaMsgEvent 微信小程序事件监听
     */
    @Async
    @EventListener(classes = WxMaMsgEvent.class, condition = "#root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.SERVICE_EVALUATION)
    public void publishMsg2ServiceEvaluation(WxMaMsgEvent wxMaMsgEvent) {
        WxMaMsgData msgData = wxMaMsgEvent.getEventData();
        if (StrUtil.isBlank(msgData.getOpenId())) {
            log.error("推送服务评价失败：{}", JSONUtil.toJsonStr(msgData));
            return;
        }
        log.info("发布服务评价消息: {}", JSONUtil.toJsonStr(msgData));
        JSONObject jsonObject = JSONUtil.parseObj(msgData.getContent());
        int consultType = jsonObject.getInt("consultType");
        String consultSessionId = jsonObject.getStr("consultSessionId");
        String targetPage = "/pages/addEval/addEval?consultType=" + consultType + "&doctorId=" + msgData.getDoctorId()
            + "&consultSessionId=" + consultSessionId + "&type=1";
        String tips = "与" + msgData.getDoctorName() + "医生的问诊已结束，【点击评价】";
        this.wxFeignClient.subscribeSendServiceEvaluation(ServiceEvaluationBO.builder()
                .openId(msgData.getOpenId())
                .targetPage(targetPage)
                .serviceItem(consultType == 1 ? "图文问诊" : "视频问诊")
                .completeTime(DateUtil.getCurrentCustomizeFormatDate("yyyy年MM月dd日 HH:mm"))
                .tips(tips)
                .build());
    }

    /**
     * 发布退款通知
     *
     * @param wxMaMsgEvent 微信小程序事件监听
     */
    @Async
    @EventListener(classes = WxMaMsgEvent.class, condition = "#root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.REFUND_NOTICE)
    public void publishMsg2RefundNotice(WxMaMsgEvent wxMaMsgEvent) {
        WxMaMsgData msgData = wxMaMsgEvent.getEventData();
        if (StrUtil.isBlank(msgData.getOpenId())) {
            log.error("推送退款通知失败：{}", JSONUtil.toJsonStr(msgData));
            return;
        }
        log.info("退款通知消息：msgData：{}", JSONUtil.toJsonStr(msgData));
        JSONObject jsonObject = JSONUtil.parseObj(msgData.getContent());
        this.wxFeignClient.subscribeSendRefundNotice(RefundNoticeBO.builder()
                .openId(msgData.getOpenId())
                .targetPage(msgData.getTargetPage())
                .orderNumber(getOrderNumber(jsonObject))
                .productName(jsonObject.getStr("productName"))
                .refundAmount("￥" + jsonObject.getStr("refundAmount"))
                .refundCause(jsonObject.getStr("refundCause"))
                .remarks("费用将原路退回您的微信账户，请注意查收")
                .build());
    }

    /**
     * 发布发货通知
     *
     * @param wxMaMsgEvent 微信小程序事件监听
     */
    @Async
    @EventListener(classes = WxMaMsgEvent.class, condition = "#root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.SHIP_NOTICE)
    public void publishMsg2ShipNotice(WxMaMsgEvent wxMaMsgEvent) {
        WxMaMsgData msgData = wxMaMsgEvent.getEventData();
        if (StrUtil.isBlank(msgData.getOpenId())) {
            log.error("推送发货通知失败：{}", JSONUtil.toJsonStr(msgData));
            return;
        }
        log.info("发货通知消息：msgData：{}", JSONUtil.toJsonStr(msgData));
        JSONObject jsonObject = JSONUtil.parseObj(msgData.getContent());
        this.wxFeignClient.subscribeSendShipNotice(ShipNoticeBO.builder()
                .openId(msgData.getOpenId())
                .targetPage(msgData.getTargetPage())
                .orderNumber(getOrderNumber(jsonObject))
                .expressDeliveryCompany(jsonObject.getStr("expressDeliveryCompany"))
                .expressDeliveryNumber(jsonObject.getStr("expressDeliveryNumber"))
                .orderItem(jsonObject.getStr("orderItem"))
                .remarks("您的药品已发货，请注意查收")
                .build());
    }

    /**
     * 发布收货提醒通知
     *
     * @param wxMaMsgEvent 微信小程序事件监听
     */
    @Async
    @EventListener(classes = WxMaMsgEvent.class, condition = "#root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.RECEIPT_REMINDER)
    public void publishMsg2ReceiptReminder(WxMaMsgEvent wxMaMsgEvent) {
        WxMaMsgData msgData = wxMaMsgEvent.getEventData();
        if (StrUtil.isBlank(msgData.getOpenId())) {
            log.error("推送收货提醒失败：{}", JSONUtil.toJsonStr(msgData));
            return;
        }
        log.info("收货提醒消息：msgData：{}", JSONUtil.toJsonStr(msgData));
        JSONObject jsonObject = JSONUtil.parseObj(msgData.getContent());
        this.wxFeignClient.subscribeSendReceiptReminder(ReceiptReminderBO.builder()
                .openId(msgData.getOpenId())
                .targetPage(msgData.getTargetPage())
                .orderNumber(getOrderNumber(jsonObject))
                .productName(jsonObject.getStr("productName"))
                .confirmReceiptTime(jsonObject.getStr("confirmReceiptTime"))
            .tips(jsonObject.getStr("tips"))
                .build());
    }

    /**
     * 发布群发消息
     *
     * @param wxMaMsgEvent 微信小程序事件监听
     */
    @Async
    @EventListener(classes = WxMaMsgEvent.class, condition = "#root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.GROUP_MESSAGE)
    public void publishMsg2GroupMessage(WxMaMsgEvent wxMaMsgEvent) {
        WxMaMsgData msgData = wxMaMsgEvent.getEventData();
        if (StrUtil.isBlank(msgData.getOpenId())) {
            log.error("推送收货提醒失败：{}", JSONUtil.toJsonStr(msgData));
            return;
        }
        this.doPublisInquiryRemind(msgData, msgData.getTargetPage(), INQUIRY_CONTENT, msgData.getContent(), "无");
    }

    /**
     * 发布续方通知
     *
     * @param wxMaMsgEvent 微信小程序事件监听
     */
    @Async
    @EventListener(classes = WxMaMsgEvent.class, condition = "#root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.CONTINUED_PRESCRIPTION)
    public void publishMsg2ContinuedPrescription(WxMaMsgEvent wxMaMsgEvent) {
        WxMaMsgData msgData = wxMaMsgEvent.getEventData();
        if (StrUtil.isBlank(msgData.getOpenId())) {
            log.error("推送续方通知失败：{}", JSONUtil.toJsonStr(msgData));
            return;
        }
        log.info("续方通知消息：msgData：{}", JSONUtil.toJsonStr(msgData));
        this.doPublisInquiryRemind(msgData, msgData.getTargetPage(), "申请续方", msgData.getContent(), PROMPT_DESC);
    }

    /**
     * 发布用药提醒
     *
     * @param wxMaMsgEvent 微信小程序事件监听
     */
    @Async
    @EventListener(classes = WxMaMsgEvent.class, condition = "#root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.MEDICATION_REMINDER)
    public void publishMsg2MedicationReminder(WxMaMsgEvent wxMaMsgEvent) {
        WxMaMsgData msgData = wxMaMsgEvent.getEventData();
        if (StrUtil.isBlank(msgData.getOpenId())) {
            log.error("推送用药提醒失败：{}", JSONUtil.toJsonStr(msgData));
            return;
        }
        log.info("用药提醒消息：msgData：{}", JSONUtil.toJsonStr(msgData));
        this.wxFeignClient.subscribeSendAdvisoryReminder(AdvisoryReminderBO.builder()
                .openId(msgData.getOpenId())
                .targetPage(msgData.getTargetPage())
                .reminderContent("您的用药时间到了，请遵医嘱按时服药")
                .appointment(msgData.getContent())
                .promptDesc("请根据医嘱处方合理用药，点击查看处方详情")
                .build());
    }

    /**
     * 发布处方支付
     *
     * @param wxMaMsgEvent
     *            微信小程序事件监听
     */
    @Async
    @EventListener(classes = WxMaMsgEvent.class,
        condition = "#root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.PRESCRIPTION_PAY)
    public void publishMsg2PrescriptionPay(WxMaMsgEvent wxMaMsgEvent) {
        WxMaMsgData msgData = wxMaMsgEvent.getEventData();
        if (StrUtil.isBlank(msgData.getOpenId())) {
            log.error("推送处方支付提醒失败：{}", JSONUtil.toJsonStr(msgData));
            return;
        }
        log.info("处方支付提醒消息：msgData：{}", JSONUtil.toJsonStr(msgData));
        JSONObject jsonObject = JSONUtil.parseObj(msgData.getContent());
        this.wxFeignClient.subscribeSendPrescriptionPay(PrescriptionPayBO.builder().openId(msgData.getOpenId())
            .targetPage(msgData.getTargetPage()).inquirerName(jsonObject.getStr("inquirerName"))
            .prescriptionTime(jsonObject.getStr("prescriptionTime")).remark(jsonObject.getStr("remark")).build());
    }

    /**
     * 发布随访订阅消息
     *
     * @param wxMaMsgEvent
     *            微信小程序事件监听
     */
    @Async
    @EventListener(classes = WxMaMsgEvent.class,
        condition = "#root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.FOLLOW_UP_STARTED +
                " || #root.args[0].msgType == " + MsgMaPublishParamBO.MsgType.FOLLOW_UP_CANCEL)
    public void publishMsg2FollowUpStarted(WxMaMsgEvent wxMaMsgEvent) {
        WxMaMsgData msgData = wxMaMsgEvent.getEventData();
        if (StrUtil.isBlank(msgData.getOpenId())) {
            log.error("推送随访任务提醒失败：{}", JSONUtil.toJsonStr(msgData));
            return;
        }
        int msgType = wxMaMsgEvent.getMsgType();
        Boolean cancelType = MsgMaPublishParamBO.MsgType.FOLLOW_UP_CANCEL == msgType;
        log.info("随访任务提醒消息：msgData：{}", JSONUtil.toJsonStr(msgData));
        this.doPublisInquiryRemind(msgData, "/pages/follow/detail/index?id=" + msgData.getFollowUpId(), "随访",
                cancelType ? "医生已取消为您制定的随访计划" : "医生为您定制了一条新的随访计划，请及时处理", msgData.getContent());
    }

    /**
     * 发布问诊通知
     *
     * @param msgData         消息内容
     * @param targetPage      跳转路径
     * @param inquiryContent  问诊内容
     * @param reminderContent 提醒内容
     * @param promptDesc      提示说明
     */
    private void doPublisInquiryRemind(WxMaMsgData msgData, String targetPage, String inquiryContent, String reminderContent, String promptDesc) {
        this.wxFeignClient.subscribeSendInquiryRemind(InquiryRemindBO.builder()
                .openId(msgData.getOpenId())
                .targetPage(targetPage)
                .inquiryDoctor(msgData.getDoctorName())
                .inquiryContent(inquiryContent)
                .reminderContent(reminderContent)
                .promptDesc(promptDesc)
                .build());
    }

    /**
     * 获取订单号
     *
     * @param jsonObject json数据
     * @return 订单号
     */
    private static String getOrderNumber(JSONObject jsonObject) {
        return jsonObject.getStr("orderNumber");
    }
}
